Skip to content

Keyboard-select composer controls with hold-modifier hints - #4271

Closed
colonelpanic8 wants to merge 17 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/composer-keyboard-shortcuts
Closed

Keyboard-select composer controls with hold-modifier hints#4271
colonelpanic8 wants to merge 17 commits into
pingdotgg:mainfrom
colonelpanic8:t3code/composer-keyboard-shortcuts

Conversation

@colonelpanic8

@colonelpanic8 colonelpanic8 commented Jul 22, 2026

Copy link
Copy Markdown

What

Makes every selector in the thread first-prompt composer keyboard-operable through the app's existing customizable keybindings system, extending the pattern already used by modelPicker.toggle.

Command Default Control
modelOptionsPicker.toggle mod+shift+e Reasoning effort / model traits menu
runtimeModePicker.toggle mod+shift+a Access level (Supervised / Auto-accept / Full access)
planMode.toggle mod+shift+p Plan ↔ Build toggle
environmentPicker.toggle mod+shift+v Branch toolbar environment
envModePicker.toggle mod+shift+l Local vs worktree
branchPicker.toggle mod+shift+b Branch selector

(mod = Ctrl on Linux/Windows, Cmd on macOS.)

All six are rebindable in Settings → Keybindings — they flow through the existing command registry, so their labels are derived by commandLabel and they're upserted into existing user configs by the server's startup sync. No new settings surface was added.

Hold-modifier hints

Holding the platform mod key reveals a small Kbd keycap on each control, in the disclosure chevron's slot. A keycap and a chevron are within a few pixels of each other, so the row barely moves, the current values (model, effort, access level, Plan/Build) stay readable, and the composer footer and branch toolbar share one treatment.

At rest, then with the modifier held:

Composer controls at rest and with the modifier held

Dark:

Composer controls with the modifier held, dark theme

Visibility is computed via shouldShowCommandHintForModifiers, which deliberately uses subset modifier matching (not the exact-match used by thread jumps) so that holding a bare Ctrl/Cmd reveals the full mod+shift+* chords.

Caps show the whole chord. Apple's glyphs (#4701) are what make that fit: ⌃⇧E sits in a chevron slot where Ctrl+Shift+E needed a row of its own.

Depends on #4701

The Apple-glyph shortcut labels live in #4701 and are carried here so this branch stands alone. Once #4701 merges, rebasing drops the duplicate.

Run-context behaviour

  • envModePicker.toggle flips local ↔ worktree directly instead of opening a two-item menu, matching how planMode.toggle already behaves. Clicking still opens the menu, which is what surfaces the worktree path. On mobile the control lives in the combined run-context sheet, which still opens.
  • The environment and workspace indicators now explain themselves while inert, distinguishing a thread that has already started from a project with only one environment. They previously rendered as muted, chevron-less controls that silently did nothing.

Fallbacks

  • Compact footer: the effort/runtime toggles open CompactComposerControlsMenu; the Plan/Build toggle still flips directly.
  • Mobile: environment / env-mode open the combined MobileRunContextSelector menu.
  • Each toggle reports whether its control was actually available; when it wasn't (locked provider, approval pending, collapsed, etc.) the command no-ops without calling preventDefault, so the browser default still fires.

Tests

Extended keybinding coverage in packages/contracts, apps/web (mac vs non-mac, subset semantics, customized bindings, no-binding, label resolution, mod-key subtraction, label stability as modifiers go down, glyph output), and apps/server defaults enumeration. Typecheck, lint, and the apps/web suite pass (182 files / 1648 tests).

🤖 Generated with Claude Code


Note

Medium Risk
Touches global shortcut resolution, label formatting (visible UX change on Linux/Windows), and thread run-context (env/workspace/branch) behavior; mitigated by extensive tests and graceful no-ops when controls are locked.

Overview
Adds six rebindable shortcuts (mod+shift+e/a/p/v/l/b) for model options, runtime mode, plan/build, environment, workspace mode, and branch pickers, wired through the existing keybindings registry and ChatView’s global keydown handler.

Composer footer gains mutually exclusive, layout-scoped picker open state (model, traits, runtime mode, compact “more” menu), new ChatComposerHandle toggles that no-op without preventDefault when unavailable, and hold-modifier hints that swap disclosure chevrons for compact keycaps via shouldShowCommandHintForModifiers (subset modifier matching).

Branch toolbar exposes BranchToolbarHandle for the same shortcuts: desktop pickers are centrally opened/toggled (one overlay at a time), mobile env/workspace shortcuts open the combined run-context menu, and desktop envModePicker.toggle flips local ↔ worktree directly instead of opening the two-item menu. Inert environment/workspace indicators get tooltips explaining why they can’t change.

Shortcut labeling is unified to Apple-style glyphs on all platforms (⌃⇧E vs Ctrl+Shift+E), with settings chips using shared formatShortcutTokenLabel.

Reviewed by Cursor Bugbot for commit 5751b4b. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add keyboard shortcuts to toggle composer and branch toolbar controls with hold-modifier hint badges

  • Adds six new keybinding commands (modelOptionsPicker.toggle, runtimeModePicker.toggle, planMode.toggle, environmentPicker.toggle, envModePicker.toggle, branchPicker.toggle) with default mod+shift+* bindings gated by !terminalFocus.
  • When the user holds the modifier keys, inline shortcut hint keycaps (ComposerShortcutKeycap) replace or supplement chevron icons on picker triggers in the composer and branch toolbar.
  • Picker open states are centrally orchestrated as mutually exclusive across the composer (model, traits, runtime mode) and branch toolbar (environment, env-mode, branch), with imperative ref-based toggle handles exposed for programmatic control from ChatView.
  • Shortcut labels now render as Apple-style glyphs (e.g., ⌃⇧P) on all platforms instead of word-based Ctrl+Shift+P format.
  • Adds useLayoutScopedOpenState to reset picker open state immediately when the rendered layout changes, and useTerminalFocus to gate shortcuts away from the terminal.
  • Behavioral Change: formatShortcutLabel output changes globally — non-macOS platforms now get glyph labels (e.g., ⌃⇧D) instead of Ctrl+Shift+D, affecting the keybindings settings UI and any other consumers.

Macroscope summarized 5751b4b.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2113c4bb-3c78-4a5c-9955-a73b2ad7578c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 22, 2026
Comment thread apps/web/src/components/chat/ChatComposer.tsx Outdated
Comment thread apps/web/src/components/chat/ChatComposer.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a new keyboard shortcut feature for composer and toolbar controls, with visual hint badges appearing when modifier keys are held. New user-facing features with new components, new hooks, and new state management patterns warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 22, 2026
Comment thread apps/web/src/components/BranchToolbar.tsx
colonelpanic8 added a commit to colonelpanic8/dotfiles that referenced this pull request Jul 22, 2026
Adds pingdotgg/t3code#4271 (keyboard-select composer controls + hold-modifier
hints) as the final entry in the applyPatches stack. The raw cumulative diff
applies with fuzz after #4258 and #4260, so it uses a plain fetchurl GitHub
link rather than a local compatibility patch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
colonelpanic8 added a commit to colonelpanic8/dotfiles that referenced this pull request Jul 22, 2026
Bump the pingdotgg/t3code#4271 fetchurl hash to the current PR head
(51135b2cc), pulling in the Cursor/Macroscope review fixes (terminal-focus
aware hints, layout-scoped picker open state, mutually-exclusive toolbar
pickers, branch-search reset). Raw cumulative diff still applies with fuzz.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch from 51135b2 to dd6cfa5 Compare July 22, 2026 14:47
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx Outdated
Comment thread apps/web/src/components/BranchToolbar.tsx
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch from 5c9615f to a371312 Compare July 22, 2026 15:45
Comment thread apps/web/src/components/BranchToolbar.tsx Outdated
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch from 8ebc09a to c2702bb Compare July 22, 2026 16:15
Comment thread apps/web/src/keybindings.ts
Comment thread apps/web/src/components/chat/ChatComposer.tsx
Comment thread apps/web/src/components/chat/composerProviderState.tsx
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch from d0c50d2 to 3a03660 Compare July 22, 2026 23:41
Comment thread apps/web/src/components/chat/ChatComposer.tsx
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch 2 times, most recently from d5ca73b to 0c612c0 Compare July 23, 2026 16:15
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Comment thread apps/web/src/components/chat/ChatComposer.tsx
Comment thread apps/web/src/components/BranchToolbar.tsx
Comment thread apps/web/src/components/BranchToolbar.tsx
Comment thread apps/web/src/components/BranchToolbar.tsx Outdated
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch 2 times, most recently from 6e28fd6 to c5ab798 Compare July 23, 2026 16:57
Comment thread apps/web/src/components/BranchToolbar.tsx
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch 2 times, most recently from 78cebd1 to 50f5812 Compare July 23, 2026 21:00
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 27, 2026
…-modifier hints)

# Conflicts:
#	apps/web/src/components/BranchToolbarBranchSelector.tsx
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 27, 2026
…-modifier hints)

# Conflicts:
#	apps/web/src/components/BranchToolbarBranchSelector.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 27, 2026
…-modifier hints)

# Conflicts:
#	apps/web/src/components/BranchToolbarBranchSelector.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 27, 2026
…-modifier hints)

# Conflicts:
#	apps/web/src/components/BranchToolbarBranchSelector.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 28, 2026
…-modifier hints)

# Conflicts:
#	apps/web/src/components/BranchToolbarBranchSelector.tsx
#	apps/web/src/components/chat/ProviderModelPicker.tsx
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch from 08e2bb9 to 6c949cf Compare July 28, 2026 02:07
colonelpanic8 and others added 14 commits July 27, 2026 19:46
Make every selector in the thread first-prompt composer keyboard-operable
through the existing customizable keybindings system, alongside the
pre-existing modelPicker.toggle command:

- modelOptionsPicker.toggle (mod+shift+e): reasoning effort / traits menu
- runtimeModePicker.toggle (mod+shift+a): access level select
- planMode.toggle          (mod+shift+p): Plan/Build toggle
- environmentPicker.toggle (mod+shift+v): branch toolbar environment
- envModePicker.toggle      (mod+shift+l): local vs worktree
- branchPicker.toggle       (mod+shift+b): branch selector

All six are rebindable in Settings -> Keybindings (labels derived by the
existing commandLabel helper) and are upserted into existing configs by the
server's startup sync. Holding the platform mod key reveals Kbd hint badges
on each control via shouldShowComposerControlHintsForModifiers, which uses
subset (not exact) modifier matching so a bare Ctrl/Cmd reveals the chords.

Compact footer routes the effort/runtime toggles to CompactComposerControlsMenu;
mobile routes environment/env-mode to the combined run-context menu. Toggles
report availability so unavailable controls leave the browser default intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hold-modifier hint chips were rendered inline inside the composer
control triggers, crowding out the current values (the model name
truncated to almost nothing). Render them instead as detached, portaled
tooltips anchored below each trigger, so the model, options, approval
and runtime-mode values stay fully visible while hints are shown. The
branch toolbar keeps its inline hints since those labels have room.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@colonelpanic8
colonelpanic8 force-pushed the t3code/composer-keyboard-shortcuts branch from 6c949cf to 5dce024 Compare July 28, 2026 02:50
The hold-modifier hints were detached tooltips anchored below their
triggers, so they landed on the branch toolbar row underneath and
collided with the inline badges already rendered there. Render the
keycap in layout instead, taking over the disclosure chevron's slot: a
cap and a chevron are within a few pixels of each other, so the row
barely moves, the current values stay readable, and the composer and
toolbar rows finally use one treatment.

Labels now drop the platform mod key — Ctrl on Linux/Windows, Cmd on
macOS — which the user must already be holding for a hint to be visible
at all. `mod+shift+e` reads `Shift+E`. Subtraction is per binding rather
than a shared-prefix assumption, so a chord rebound to `mod+alt+e`
renders `Alt+E` beside its neighbours, and the label does not reflow as
further modifiers go down.

Also:

- `envModePicker.toggle` flips local <-> worktree directly instead of
  opening a two-item menu, matching `planMode.toggle`. Clicking still
  opens the menu, which is what surfaces the worktree path.
- The environment and workspace indicators explain themselves while
  inert, distinguishing a thread that has already started from a project
  with only one environment. They previously rendered as muted,
  chevron-less controls that silently did nothing.
Shortcut labels spelled modifiers out on Linux and Windows (`Ctrl+Shift+E`)
while already using Apple's glyphs on macOS. Use one representation
everywhere: `⌃⌥⇧` for control, option and shift on every platform, `⌘`
for command on macOS, in Apple's canonical order with no separators.

Non-letter keys get their glyphs too, so `mod+backspace` is `⌃⌫` rather
than `⌃Backspace`. Keys with no established glyph — function keys,
punctuation — keep their word. A non-mac meta/super key has no Apple
glyph, so it stays `Super` rather than borrowing `⌘`, which would be a
lie about which key to press.

This matters most for the hold-modifier keycaps, where `⌃⇧E` fits a
control's chevron slot and `Ctrl+Shift+E` does not, but the same
representation now applies to the command palette, sidebar chips,
terminal tooltips, and the keybindings settings table. That table
rendered each token as its own chip via a separate platform conditional,
which had already drifted (`Ctrl` beside `⇧`); it now shares the one
token formatter.
Comment thread apps/web/src/components/BranchToolbar.tsx
Comment thread apps/web/src/components/BranchToolbar.tsx
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 28, 2026
…old-modifier hints)

# Conflicts:
#	apps/web/src/keybindings.test.ts
colonelpanic8 added a commit to colonelpanic8/t3code that referenced this pull request Jul 28, 2026
…old-modifier hints)

# Conflicts:
#	apps/web/src/keybindings.test.ts
The caps dropped the platform mod key on the grounds that the user was
already holding it. That reasoning was sound when a cap read `Shift+E`
and every pixel counted, but the Apple glyphs shrank the full chord to
`⌃⇧E` — about 8px wider than `⇧E` — so the saving no longer pays for
making the reader reconstruct which modifier the hint belongs to.

Showing the whole chord also matches how macOS menus print shortcuts,
and it removes a function: the per-command gate already decides whether
a hint is visible, so the label is now just `shortcutLabelForCommand`.
@colonelpanic8

Copy link
Copy Markdown
Author

Superseded by #4701, which carries the Apple-glyph shortcut labels on their own against main.

The composer hold-modifier hint work from this branch (keycaps in the disclosure-chevron slot, direct local ↔ worktree toggle, self-explaining locked run-context indicators) stays on colonelpanic8:t3code/composer-keyboard-shortcuts if it's wanted later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant